package com.yuelao.nio;

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author FLY
 * @version v1.0
 * @project yuelao-server
 * @date 2018/3/1 16:00
 * @修改记录
 * 版本       修改人         修改时间         修改内容描述
 * --------------------------------------------------
 * <p>
 * --------------------------------------------------
 */
public class BufferDemo {
    /**
     *
        当你写数据到Buffer中时，position表示当前的位置。初始的position值为0.
        当一个byte、long等数据写到Buffer后， position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.

        当读取数据时，也是从某个特定位置读。当将Buffer从写模式切换到读模式，position会被重置为0.
        当从Buffer的position处读取数据时，position向前移动到下一个可读的位置。

        limit
        在写模式下，Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下，limit等于Buffer的capacity。

        当切换Buffer到读模式时， limit表示你最多能读到多少数据。
        因此，当切换Buffer到读模式时，limit会被设置成写模式下的position值。
        换句话说，你能读到之前写入的所有数据（limit被设置成已写数据的数量，这个值在写模式下就是position


         Java NIO 有以下Buffer类型
         ByteBuffer
         MappedByteBuffer
         CharBuffer
         DoubleBuffer
         FloatBuffer
         IntBuffer
         LongBuffer
         ShortBuffer
     */
    public static void main(String[] args) throws Exception{
        RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
        FileChannel inChannel = aFile.getChannel();
        ByteBuffer buf = ByteBuffer.allocate(48);
        int bytesRead = inChannel.read(buf);
        while (bytesRead != -1) {
            buf.flip();
            while(buf.hasRemaining()){
                System.out.print((char) buf.get());
            }
            buf.rewind();
            System.out.println("读完：" + buf.get());
            //rewind()方法
            //Buffer.rewind()将position设回0，所以你可以重读Buffer中的所有数据。limit保持不变，仍然表示能从Buffer中读取多少个元素（byte、char等）。


            // clear()与compact()方法
            // 如果调用的是clear()方法，position将被设回0，limit被设置成 capacity的值。换句话说，Buffer 被清空了。
            // compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面
            buf.clear(); //make buffer ready for writing

            //通过调用Buffer.mark()方法，可以标记Buffer中的一个特定position。
            // 之后可以通过调用Buffer.reset()方法恢复到这个position

            bytesRead = inChannel.read(buf);
        }
        aFile.close();

        // 测试transferForm
        BufferDemo bufferDemo = new BufferDemo();
        //bufferDemo.transferFormDemo();
        bufferDemo.transferToDemo();

    }

    /**
     * Scattering
     * @throws Exception
     */
    public void scatter() throws Exception{
        RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
        FileChannel inChannel = aFile.getChannel();
        ByteBuffer head = ByteBuffer.allocate(48);
        ByteBuffer body = ByteBuffer.allocate(1024);
        ByteBuffer[] buffers = {head, body};
        inChannel.read(buffers);
        aFile.close();;
    }

    /**
     * gather
     * @throws Exception
     */
    public void gather() throws Exception {
        RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
        FileChannel inChannel = aFile.getChannel();
        ByteBuffer head = ByteBuffer.allocate(48);
        ByteBuffer body = ByteBuffer.allocate(1024);
        ByteBuffer[] buffers = {head, body};
        inChannel.write(buffers);
        aFile.close();
    }

    /**
     * FileChannel的transferFrom()方法可以将数据从源通道传输到FileChannel中
     * @throws Exception
     */
    public void transferFormDemo() throws Exception{
        RandomAccessFile fromFile = new RandomAccessFile("data/nio-data.txt", "rw");
        FileChannel fromChannel = fromFile.getChannel();
        RandomAccessFile toFile = new RandomAccessFile("data/toFile.txt", "rw");
        FileChannel toChannel = toFile.getChannel();
        long position = 0;
        long count = fromChannel.size();
        toChannel.transferFrom(fromChannel, position, count);
        fromFile.close();
        toFile.close();
    }

    public void transferToDemo() throws Exception{
        RandomAccessFile fromFile = new RandomAccessFile("data/nio-data.txt", "rw");
        FileChannel fromChannel = fromFile.getChannel();
        RandomAccessFile toFile = new RandomAccessFile("data/toFile.txt", "rw");
        FileChannel tochannel = toFile.getChannel();
        long position = 0;
        long count = fromChannel.size();
        fromChannel.transferFrom(tochannel, position, count);
        toFile.close();
        fromFile.close();
    }
}
